#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#include <net/if.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <time.h>

typedef struct can_filter CAN_FILTER;
typedef struct can_frame CAN_FRAME;

/*

#define CAN_EFF_FLAG 0x80000000U //扩展帧的标识
#define CAN_RTR_FLAG 0x40000000U //远程帧的标识
#define CAN_ERR_FLAG 0x20000000U //错误帧的标识，用于错误检查

#define CAN_SFF_MASK 0x000007FFU //standard frame format (SFF)
#define CAN_EFF_MASK 0x1FFFFFFFU //extended frame format (EFF)
#define CAN_ERR_MASK 0x1FFFFFFFU //omit EFF, RTR, EFF flags

bit 0-28: CAN ID(11/29 bit)
bit 29  : error message frame flag (0 = data frame, 1= error message)
bit 30  : remote transmission request flag (1 = rtr frame)
bit 31  : frame format flag (0 = standard 11 bit, 1 = extended 29 bit)

struct can_frame {
canid_t can_id;   //CAN 标识符
__u8 can_dlc;     //数据的长度
__u8 data[8];     //数据
};

struct can_filter {
canid_t can_id;
canid_t can_mask;
};

struct can_filter rfilter[2];
rfilter[0].can_id = 0x123;
rfilter[0].can_mask = CAN_SFF_MASK;

rfilter[1].can_id = 0x200;
rfilter[1].can_mask = 0x700;
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));//设置规则
过滤器匹配规则:
<received_can_id> & mask == can_id & mask
*/

static u_int8_t BMS_ADDRESS = 0xf4;
static u_int8_t CHARGER_ADDRESS = 0x56;

static u_int8_t BCP_PGN = 0x06;
static u_int8_t CTS_PGN = 0x07;
static u_int8_t CML_PGN = 0x08;
static u_int8_t BRO_PGN = 0x09;
static u_int8_t CRO_PGN = 0x0A;
static u_int8_t BCL_PGN = 0x10;
static u_int8_t BCS_PGN = 0x11;
static u_int8_t CCS_PGN = 0x12;
static u_int8_t BSM_PGN = 0x13;

static u_int8_t BCP_PRI = 7;
static u_int8_t CTS_PRI = 6;
static u_int8_t CML_PRI = 6;
static u_int8_t BRO_PRI = 4;
static u_int8_t CRO_PRI = 4;
static u_int8_t BCL_PRI = 6;
static u_int8_t BCS_PRI = 6;
static u_int8_t CCS_PRI = 6;
static u_int8_t BSM_PRI = 6;

void decodeCANDCChargingNetwork(CAN_FRAME *ptframe)
{
    //do something with the received CAN frame
    /*
    CAN_ID 4 bytes:
    bit 0-7: SA(source address)
    bit 8-15: PS(target address)
    bit 16-23: PF(PCG)
    bit 24-28: P 3 bit, R 1 bit, DP 1 bit.
    */

	if (ptframe == NULL)
	{
		printf("Input ptframe is NULL.");
		return;
	}

    u_int8_t SA = ptframe->can_id & 0x000000FF;
    u_int8_t PS = (ptframe->can_id & 0x0000FF00) >> 8;
    u_int8_t PF = (ptframe->can_id & 0x00FF0000) >> 16;
    u_int8_t Priority = (ptframe->can_id & 0x1C000000) >> 26;
//    printf("测试数据：0x%08x\n", (ptframe->can_id & 0x000000FF));
//    printf("测试数据：0x%08x\n", (ptframe->can_id & 0x0000FF00) >> 8);
//    printf("测试数据：0x%08x\n", (ptframe->can_id & 0x00FF0000) >> 16);
//    printf("测试数据：0x%08x\n", (ptframe->can_id & 0xFF000000) >> 24);
//    printf("测试数据：0x%08x\n", (ptframe->can_id & 0x38000000) >> 27);

    //检验帧格式： 标准帧还是扩展帧
    if (ptframe->can_id & CAN_EFF_FLAG)
        printf("\nReceive Extended frames CAN_ID:<0x%08x> \n", ptframe->can_id & CAN_EFF_MASK);
    else
        printf("\nReceive Standard frames CAN_ID:<0x%03x> \n", ptframe->can_id & CAN_SFF_MASK);

    if (SA == BMS_ADDRESS)
    {
        printf("Source Address：BMS");
    }
    else if (SA == CHARGER_ADDRESS)
    {
        printf("Source Address：Charging piles");
    }
    else
    {
        printf("Source Address：Unknown");
    }

    if (PS == BMS_ADDRESS)
    {
        printf(", Destination Address：BMS");
    }
    else if (PS == CHARGER_ADDRESS)
    {
        printf(", Destination Address：Charging piles");
    }
    else
    {
        printf(", Destination Address：Unknown");
    }

    printf("\nPriority: %u", Priority);

    if (Priority == BCP_PRI && PF == BCP_PGN && PS == CHARGER_ADDRESS && SA == BMS_ADDRESS)
    {
        printf(", Message Description: BCP message, charging parameters of the power battery.\n");
    }
    else if (Priority == CTS_PRI && PF == CTS_PGN && PS == BMS_ADDRESS && SA == CHARGER_ADDRESS)
    {
        printf(", Message Description: CTS packets, the charging pile sends time synchronization information.\n");
    }
    else if (Priority == CML_PRI && PF == CML_PGN && PS == BMS_ADDRESS && SA == CHARGER_ADDRESS)
    {
        printf(", Message Description: CML message, the maximum output capacity of the charger.\n");
    }
    else if (Priority == BRO_PRI && PF == BRO_PGN && PS == CHARGER_ADDRESS && SA == BMS_ADDRESS)
    {
        printf(", Message Description: BRO message, battery charging readiness status.\n");
    }
    else if (Priority == CRO_PRI && PF == CRO_PGN && PS == BMS_ADDRESS && SA == CHARGER_ADDRESS)
    {
        printf(", Message Description: CRO message, the charging pile output is ready.\n");
    }
    else if (Priority == BCL_PGN && PF == BCL_PGN && PS == CHARGER_ADDRESS && SA == BMS_ADDRESS)
    {
        printf(", Message Description: BCL message, battery charging requirements.\n");
    }
    else if (Priority == BCS_PGN && PF == BCS_PGN && PS == CHARGER_ADDRESS && SA == BMS_ADDRESS)
    {
        printf(", Message Description: BCS message, Total Battery Charge Status.\n");
    }
    else if (Priority == CCS_PGN && PF == CCS_PGN && PS == BMS_ADDRESS && SA == CHARGER_ADDRESS)
    {
        printf(", Message Description: CCS packet, charging status of the charging pile.\n");
    }
    else if (Priority == BSM_PGN && PF == BSM_PGN && PS == CHARGER_ADDRESS && SA == BMS_ADDRESS)
    {
        printf(", Message Description: BSM message, power battery status information.\n");
    }
    else
    {
        printf(", Message Description: Unknown\n");
    }
	return;
}

int socketCan(int *psockfd)
{
	struct ifreq ifr = {0};
    struct sockaddr_can can_addr = {0};
    int ret;

	if(psockfd == NULL)
	{
        perror("Input psockfd is NULL!");
        return -1;
	}
	
    //打开套接字
    *psockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
    if(0 > *psockfd)
    {
        perror("socket error!");
        return -1;
    }

    //指定 can0 设备
    strcpy(ifr.ifr_name, "can0");
    ioctl(*psockfd, SIOCGIFINDEX, &ifr);
    can_addr.can_family = AF_CAN;
    can_addr.can_ifindex = ifr.ifr_ifindex;

    //将 can0 与套接字进行绑定
    ret = bind(*psockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
    if(0 > ret)
    {
        perror("bind socket error!");
        close(*psockfd);
        return -1;
    }
	return 0;
}

void showFrame(CAN_FRAME *ptframe)
{
	char buf[20] = {0};

    time_t timep;
    time(&timep);

    struct tm *p;
    p = gmtime(&timep);

    snprintf(buf, 20, "%d-%d-%d %02d:%02d:%02d", 1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday, 8 + p->tm_hour, p->tm_min, p->tm_sec);

	printf("\n          Time         |  Direction  |  FrameFormat  |  FrameType  |    CAN_ID    |  DLC  |  DATA  ");
	printf("\n  %s  |", buf);

	if (ptframe->can_id & CAN_RTR_FLAG)
    {
		printf("   Receive   |  Remote       |");
    }
	else
	{
		printf("   Receive   |  Data         |");
	}
		
	//检验帧格式： 标准帧还是扩展帧
    if (ptframe->can_id & CAN_EFF_FLAG)
	{
        printf("  Extended   |  0x%08x  |", ptframe->can_id & CAN_EFF_MASK);
	}
    else
	{
		printf("  Standard   |    0x%03x     |", ptframe->can_id & CAN_SFF_MASK);
	}

    if (ptframe->can_id & CAN_RTR_FLAG)
	{
		printf("  -  |  -  ");
	}
	else
	{
		printf("   %d   |  ", ptframe->can_dlc);
	}
    //打印数据
    for(int i = 0; i < ptframe->can_dlc; i++)
	{
        printf("%02x ", ptframe->data[i]);
	}
}

#define MAX_FILTER_NUM 5
CAN_FILTER g_rfilter[MAX_FILTER_NUM] = {0};
unsigned int g_filter_num = 0;

int setFilterParam(int sockfd, char * ptParam, int paramLen)
{
	if (ptParam != NULL && g_filter_num < MAX_FILTER_NUM)
    {
		memset(&g_rfilter[g_filter_num], 0, sizeof(CAN_FILTER));

	    sscanf(ptParam, "%x", &g_rfilter[g_filter_num].can_id);
        printf("\nFilter receiving CAN_ID: <%x> \n", g_rfilter[g_filter_num].can_id);

        switch(paramLen)
        {
            case 3:
                g_rfilter[g_filter_num].can_mask = CAN_SFF_MASK;
				g_filter_num++;
            break;
            case 8:
                g_rfilter[g_filter_num].can_mask = CAN_EFF_MASK;
				g_filter_num++;
            break;
            default:
                perror("\nInput CAN_ID error!\n");
				return -1;
        }    
    }
	return 0;
}

int decodeTemp(CAN_FRAME *ptframe)
{
    //printf("[test]:show data[0]:%x.\n", ptframe->data[0]);
    if (ptframe->data[0] != 0)
    {
        printf("\nTemperature data is abnormal!\n");
        return -1;
    }

   // printf("[test]:show data[1]:%x\n", ptframe->data[1]);

    int temp = ptframe->data[1];
    //printf("[test]:show data: %d.\n", data);
    //long int temp = strtol(data, NULL, 16);

    printf("\nThe currently acquired temperature is %d ℃.\n", temp);

    return 0;
}

int main(int argc, char **argv)
{
    CAN_FRAME frame = {0};

    int sockfd = -1;
    int i;

    if(argv[1] != NULL && strcmp(argv[1], "-h") == 0)
    {
        printf("\nreceive [CAN_ID]...\n Max filter CAN_ID number: 5\n CAN_ID len is 3 or 8\n");
        return 0;
    }

	if (0 > socketCan(&sockfd))
	{
		return 0;
	}

    if (argc > 1)
    {
        g_filter_num = 0;
        for (i = 1; i < argc; i++)
	    {
            printf("Input para %d: %s\n", i, argv[i]);
		    if (0 > setFilterParam(sockfd, argv[i], strlen(argv[i])))
            {
                continue;
            }
        }
	    //设置过滤规则
        setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &g_rfilter, sizeof(CAN_FILTER)*g_filter_num);
        //接收数据
    }

    while(1)
    {
        if(0 > read(sockfd, &frame, sizeof(struct can_frame)))
        {
            perror("Read socket error!");
            break;
        }

        // 校验是否接收到错误帧
        if(frame.can_id & CAN_ERR_FLAG)
        {
            printf("Receive Error frame!\n");
            break;
        }

        showFrame(&frame);

        printf("\n");

        // printf("can id:%d\n", frame.can_id);
        if(frame.can_id == 281)
        {
            // printf("[test]:id 281\n");
            decodeTemp(&frame);
        }

        // if (frame.can_id & CAN_EFF_FLAG)
        // {
        //     decodeCANDCChargingNetwork(&frame);
        // }
    }

    //关闭套接字
    close(sockfd);
    return 0;
}
